package spring.fox;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import spring.fox.annotation.EnableFox;
import spring.fox.processor.RpcReferenceBeanPostProcessor;
import spring.fox.processor.RpcServiceBeanDefinitionRegisteredProcessor;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * @author cuichao
 * @Description: SpringFoxImportBeanDefinitionRegistrar
 * @Date: create in 2021/3/3 14:42
 */
public class SpringFoxImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    private final String BASE_PACKAGE = "basePackages";

    private final String BASE_PACKAGE_CLASS = "basePackageClasses";

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

        //得到包扫描路径
        Set<String> packagesToScan = getPackagesToScan(metadata);

        registerRpcServiceRegisterProcessor(packagesToScan, registry);

        registerRpcReferenceRegisterProcessor(registry);

    }

    /**
     * 注册Rpc服务处理器
     *
     * @param packagesToScan
     * @param registry
     */
    private void registerRpcServiceRegisterProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(RpcServiceBeanDefinitionRegisteredProcessor.class);
        builder.addConstructorArgValue(packagesToScan);
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
    }

    /**
     * 注册Rpc消费处理器
     * @param registry
     */
    private void registerRpcReferenceRegisterProcessor(BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(RpcReferenceBeanPostProcessor.class);
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        registry.registerBeanDefinition(RpcReferenceBeanPostProcessor.BEAN_NAME,beanDefinition);
    }


    private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
        //获取注解信息
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(EnableFox.class.getName()));
        String[] basePackages = attributes.getStringArray(BASE_PACKAGE);
        Class<?>[] basePackageClasses = attributes.getClassArray(BASE_PACKAGE_CLASS);
        //得到包扫描的集合
        Set<String> packagesToScan = new LinkedHashSet<String>();
        packagesToScan.addAll(Arrays.asList(basePackages));
        for (Class<?> basePackageClass : basePackageClasses) {
            packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
        }
        if (packagesToScan.isEmpty()) {
            return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
        }
        return packagesToScan;
    }
}
